package com.wxmp.wxcms.ctrl;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wxmp.core.common.Json;
import com.wxmp.core.common.OAuthJsToken;
import com.wxmp.core.common.WxPayConfig;
import com.wxmp.core.util.IpUtils;
import com.wxmp.core.util.PayUtil;
import com.wxmp.core.util.StringUtil;
import com.wxmp.wxapi.process.HttpMethod;
import com.wxmp.wxapi.process.WxApi;
import com.wxmp.wxcms.domain.UserOrder;
import com.wxmp.wxcms.service.UserOrderService;

/**
 * @Description: 微信支付控制器
 * @date: 2018年6月19日
 * @Author: fuziKong
 * https://www.zzojjd.com/
 */
@RestController
@RequestMapping("/weixinpay")
public class WeixinPayController{

    private Logger logger = LoggerFactory.getLogger(getClass());
    
    @Autowired
    private UserOrderService userOrderService;
    /**
     * 小程序后台登录，向微信平台发送获取access_token请求，并返回openId
     * @param code
     * @return openid
     * @throws WeixinException
     * @throws IOException
     */
    @RequestMapping(value="/login",method=RequestMethod.GET,produces="application/json; charset=UTF-8")
    public Map<String, Object> login(String code) throws  IOException {
    	logger.info("==[WeixinPayController.login]方法==code==================" + code);
        if (code == null || code.equals("")) {
            throw new IOException("invalid null, code is null.");
        }

        Map<String, Object> ret = new HashMap<String, Object>();
        //拼接参数
        String param = "?grant_type=" + WxPayConfig.GRANT_TYPE + "&appid=" + WxPayConfig.APPID + "&secret=" + WxPayConfig.SECRET + "&js_code=" + code;

        //调用获取access_token接口
        JSONObject jsonObj = WxApi.httpsRequest("https://api.weixin.qq.com/sns/jscode2session" + param, HttpMethod.GET) ;  
        logger.info("==[WeixinPayController.login]方法==jsonObj==================" + jsonObj);
        //根据请求结果判定，是否验证成功
        if (jsonObj != null) {
            Object errcode = jsonObj.get("errcode");
            if (errcode != null) {
                //返回异常信息
                throw new IOException("登录出错.");
            }
            logger.info("==[WeixinPayController.login]方法==调用获取access_token接口==="+jsonObj.toJSONString());
            ObjectMapper mapper = new ObjectMapper();
            OAuthJsToken oauthJsToken = mapper.readValue(jsonObj.toJSONString(),OAuthJsToken.class);
            ret.put("data", oauthJsToken.getOpenid());
            ret.put("success", true);
            ret.put("msg", "授权成功!");        
        }else {
        	ret.put("success", false);
        	ret.put("msg", "授权失败!");        	
        }
        return ret;
    }

    /**
     * @Description: 发起微信支付
     * @param openid
     * @param request
     * @author: fuziKong
     * @date: 2018年6月19日
     * 测试openId: ohPFE0qt0bnyHIlXm9PL5aBxeJRU
     */
    @RequestMapping(value="/wxPay",method=RequestMethod.POST,produces="application/json; charset=UTF-8")
    public Json wxPay(String openid,String money,String days,HttpServletRequest request){
        Json json = new Json();
        Map<String,String> map = null;
        try{
            //生成的随机字符串
            String nonce_str = StringUtil.getRandomStringByLength(32);
            //商品名称
            String body = "oujia";
            //获取本机的ip地址
            String spbill_create_ip = IpUtils.getIpAddr(request);           
            logger.info("==[WeixinPayController.wxPay]方法==openid==" + openid + "=====================");
            String orderNo = "123456789"+new Random().nextInt(10000);
            //String money = "1";//支付金额，单位：分，这边需要转成字符串类型，否则后面的签名会失败
            logger.info("==[WeixinPayController.wxPay]方法==openid=="+openid + "==money=" +money+"==days="+days);
            Map<String, String> packageParams = new TreeMap<String, String>();
            packageParams.put("appid", WxPayConfig.APPID);
            packageParams.put("mch_id", WxPayConfig.MCH_ID);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", body);
            packageParams.put("out_trade_no", orderNo);//商户订单号
            packageParams.put("total_fee", money);//支付金额，这边需要转成字符串类型，否则后面的签名会失败
            packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", WxPayConfig.NOTIFY_URL);
            packageParams.put("trade_type", WxPayConfig.TRADETYPE);
            packageParams.put("openid", openid);
            logger.info("==[WeixinPayController.wxPay]方法map中的传入参数:" + packageParams);
            // 除去数组中的空值和签名参数
            packageParams = PayUtil.paraFilter(packageParams);
            String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串

            //MD5运算生成签名，这里是第一次签名，用于调用统一下单接口
            String mysign = PayUtil.sign(prestr, WxPayConfig.KEY, "utf-8").toUpperCase();
            logger.info("==[WeixinPayController.wxPay]方法==第一次签名：" + mysign + "=====================");

            //拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
            String xml = "<xml>" + "<appid>" + WxPayConfig.APPID + "</appid>"
                    + "<body><![CDATA[" + body + "]]></body>"
                    + "<mch_id>" + WxPayConfig.MCH_ID + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + WxPayConfig.NOTIFY_URL + "</notify_url>"
                    + "<openid>" + openid + "</openid>"
                    + "<out_trade_no>" + orderNo + "</out_trade_no>"
                    + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
                    + "<total_fee>" + money + "</total_fee>"
                    + "<trade_type>" + WxPayConfig.TRADETYPE + "</trade_type>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";

            logger.info("==[WeixinPayController.wxPay]方法==调试模式_统一下单接口>>请求XML数据：\n" + xml);

            //调用统一下单接口，并接受返回的结果
            String result = PayUtil.httpRequest(WxPayConfig.PAY_URL, "POST", xml);
            logger.info("==[WeixinPayController.wxPay]方法==调试模式_统一下单接口<<返回XML数据：\n" + result);

            // 将解析结果存储在HashMap中
            map = PayUtil.doXMLParse(result);
            String return_code = (String) map.get("return_code");//返回状态码

            //返回给移动端需要的参数
            Map<String, Object> response = new TreeMap<String, Object>();
            if(return_code == "SUCCESS" || return_code.equals(return_code)){
                // 业务结果
                String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
                String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳，自1970年以来的秒数 
                response.put("nonceStr", nonce_str);
                response.put("appId", WxPayConfig.APPID);
                response.put("package", "prepay_id=" + prepay_id);
                response.put("timeStamp", timeStamp);//这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
                String stringSignTemp = "appId=" + WxPayConfig.APPID + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=" + WxPayConfig.SIGNTYPE + "&timeStamp=" + timeStamp;
                //再次签名，这个签名用于小程序端调用wx.requesetPayment方法
                String paySign = PayUtil.sign(stringSignTemp, WxPayConfig.KEY, "utf-8").toUpperCase();
                response.put("paySign", paySign);
                logger.info("==[WeixinPayController.wxPay]方法==第二次签名：" + paySign + "=====================");

                //更新订单信息
                //业务逻辑代码
            }
            
            json.setSuccess(true);
            json.setData(response);
            json.setMsg("调用成功!");
        }catch(Exception e){
            e.printStackTrace();
            json.setSuccess(false);
            json.setMsg(map.get("err_code_des"));
        }
        return json;
    }

    /**
     * @Description:微信支付
     * @return
     * @author fuziKong
     * @throws Exception
     * @date: 2018年6月19日
     * 微信返回的XML数据
     <?xml version="1.0" encoding="utf-8"?>
    <xml>
      <appid><![CDATA[wxf45fd51095e16774]]></appid>
      <bank_type><![CDATA[CFT]]></bank_type>
      <cash_fee><![CDATA[5]]></cash_fee>
      <fee_type><![CDATA[CNY]]></fee_type>
      <is_subscribe><![CDATA[N]]></is_subscribe>
      <mch_id><![CDATA[1505569321]]></mch_id>
      <nonce_str><![CDATA[hvepbrh6uyvm7wocf8inl8k9y9dpiid3]]></nonce_str>
      <openid><![CDATA[o0Fr946CrzDeIMWGK2Y8yosseEZY]]></openid>
      <out_trade_no><![CDATA[1234567892645]]></out_trade_no>
      <result_code><![CDATA[SUCCESS]]></result_code>
      <return_code><![CDATA[SUCCESS]]></return_code>
      <sign><![CDATA[D4021F04B2122876AD45DDE34CCC0B56]]></sign>
      <time_end><![CDATA[20180627235329]]></time_end>
      <total_fee>5</total_fee>
      <trade_type><![CDATA[JSAPI]]></trade_type>
      <transaction_id><![CDATA[4200000130201806272009814257]]></transaction_id>
    </xml>
     **/
    @RequestMapping(value="/wxNotify")
    public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
    	logger.info("==[WeixinPayController.wxPay]方法=====");
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while((line = br.readLine())!=null){
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        logger.info("==[WeixinPayController.wxPay]方法==接收到的报文："+notityXml);
        Map<String,String> map = PayUtil.doXMLParse(notityXml);
        logger.info("==[WeixinPayController.wxPay]方法==报文封装成Map："+map);
        String returnCode = (String) map.get("return_code");
        logger.info("==[WeixinPayController.wxPay]方法==报文map.get(return_code)：=="+returnCode+"==\"SUCCESS\".equals(returnCode)"+"SUCCESS".equals(returnCode));
        /**此处添加自己的业务逻辑代码start**/
    	int days = 0;  //延长的天数
    	int total = Double.valueOf(map.get("total_fee")).intValue();
		if (total == 5) {
			days = 10;
		} else if (total == 10) {
			days = 31;
		} else if (total == 30) {
			days = 90;
		} else if (total == 50) {
			days = 180;
		} else if (total == 90) {
			days = 365;
		} else if (total == 500) {
			days = 3650;
		}
		logger.info("==[WeixinPayController.wxPay]方法==total=="+total+",days=="+days);
    	 UserOrder userOrder = new UserOrder();
         userOrder.setNonceStr(map.get("nonce_str"));
         userOrder.setOutTradeno(map.get("out_trade_no"));
         userOrder.setTotalFee(  Double.valueOf(map.get("total_fee"))  );
         userOrder.setAddDays(days);
         userOrder.setSpbillCreateip(IpUtils.getIpAddr(request));
         userOrder.setOpenid(map.get("openid"));
         //userOrder.setPrepayId(prepay_id);
         logger.info("==[WeixinPayController.wxPay]方法==添加订单=userOrder=="+userOrder);
         userOrderService.add(userOrder);
        if("SUCCESS".equals(returnCode)){
            //验证签名是否正确
            boolean verifyResult = PayUtil.verify(PayUtil.createLinkString(map), (String)map.get("sign"), WxPayConfig.KEY, "utf-8");
            logger.info("==[WeixinPayController.wxPay]方法==签名验证结果=verifyResult=="+userOrder);
            if(verifyResult){
                /**此处添加自己的业务逻辑代码end**/
                //通知微信服务器已经支付成功
                resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
            }
        }else{
                resXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";
        }
        logger.info("==[WeixinPayController.wxPay]方法==resXml======"+resXml+"====");
        logger.info("==[WeixinPayController.wxPay]方法==微信支付回调数据结束=====");
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }
}